package com.dly.blog.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.dly.blog.content.RedisContent;
import com.dly.blog.domain.Comment;
import com.dly.blog.domain.Content;
import com.dly.blog.domain.ro.PageRO;
import com.dly.blog.domain.vo.CountVO;
import com.dly.blog.domain.vo.content.ContentHotVO;
import com.dly.blog.domain.vo.content.ContentShowVO;
import com.dly.blog.mapper.CommentMapper;
import com.dly.blog.mapper.ContentMapper;
import com.dly.blog.provider.user.UserProvider;
import com.dly.blog.service.ContentService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dly.blog.utile.RedisUtils;
import com.dly.blog.utile.SecurityUtils;
import org.springframework.stereotype.Service;
import com.dly.blog.domain.vo.content.ContentVO;
import com.dly.blog.domain.ro.content.ContentPageRO;
import com.dly.blog.domain.ro.content.ContentAddRO;
import com.dly.blog.domain.ro.content.ContentEditRO;
import com.dly.blog.domain.vo.PageVO;
import org.springframework.beans.BeanUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.transaction.annotation.Transactional;
import lombok.AllArgsConstructor;
import cn.hutool.core.collection.ListUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static com.dly.blog.exception.ContentExceptionEnum.NO_PERMISSIONS_EDIT_OTHER_CONTENT;

/**
 * <p>
 * 文章 服务实现类
 * </p>
 *
 * @author DLY
 * @since 2024-01-24 09:53:18
 */
@Service
@AllArgsConstructor
public class ContentServiceImpl extends ServiceImpl<ContentMapper, Content> implements ContentService {

    private final UserProvider userProvider;

    private final RedisUtils redisUtils;

    private final CommentMapper commentMapper;

    @Override
    public PageVO<ContentVO> getContentPage(ContentPageRO contentPageRO) {
        Page<Content> page = baseMapper.selectPage(contentPageRO.buildIPage(), new LambdaQueryWrapper<>());
        return PageVO.buildMyBatis(page, content -> {
            ContentVO contentVO = new ContentVO();
            BeanUtils.copyProperties(content, contentVO);
            return contentVO;
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addContent(ContentAddRO contentAddRO) {
        Content content = new Content();
        BeanUtils.copyProperties(contentAddRO, content);
        baseMapper.insert(content);
    }

    @Override
    public ContentVO getContent(String id) {
        Content content = baseMapper.selectById(id);
        ContentVO contentVO = new ContentVO();
        BeanUtils.copyProperties(content, contentVO);
        contentVO.setCreateName(userProvider.selectById(content.getCreateUser()).getUserName());
        Set<String> supports = redisUtils.getSet(RedisContent.CONTENT_SUPPORT + id);
        Set<String> favorite = redisUtils.getSet(RedisContent.CONTENT_FAVORITE + id);
        Set<String> read = redisUtils.getSet(RedisContent.READ_NUM + id);
        contentVO.setSupportNum(supports.size());
        contentVO.setFavoriteNum(favorite.size());
        contentVO.setReadNum(read.size());
        contentVO.setFavorite(favorite.contains(SecurityUtils.getUserId()));
        contentVO.setSupport(supports.contains(SecurityUtils.getUserId()));
        Long commentNum = commentMapper.selectCount(new LambdaQueryWrapper<Comment>().eq(Comment::getContentId, id));
        contentVO.setCommentNum(Math.toIntExact(commentNum));
        return contentVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeContent(String[] ids) {
        List<Content> contents = baseMapper.selectBatchIds(ListUtil.toList(ids));
        contents.stream().filter(content -> ObjectUtil.notEqual(SecurityUtils.getUserId(), content.getCreateUser()))
                .findFirst()
                .ifPresent((content)-> {
                   throw NO_PERMISSIONS_EDIT_OTHER_CONTENT.getContentException();
                });
        ;
        baseMapper.deleteBatchIds(ListUtil.toList(ids));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editContent(ContentEditRO contentEditRO) {
        Content contentOld = baseMapper.selectById(contentEditRO.getId());
        if(ObjectUtil.notEqual(SecurityUtils.getUserId(), contentOld.getCreateUser())){
            throw NO_PERMISSIONS_EDIT_OTHER_CONTENT.getContentException();
        }
        Content content = new Content();
        BeanUtils.copyProperties(contentEditRO, content);
        baseMapper.updateById(content);
    }

    @Override
    public PageVO<ContentShowVO> getContentShowPage(ContentPageRO contentPageRO) {
        Page<ContentShowVO> contentShowPage = baseMapper.getContentShowPage(contentPageRO.buildIPage(), contentPageRO);
        return PageVO.buildMyBatis(contentShowPage, contentShowVO -> {
            //获取点赞数据
            Set<String> supports = redisUtils.getSet(RedisContent.CONTENT_SUPPORT + contentShowVO.getId());
            Set<String> favorite = redisUtils.getSet(RedisContent.CONTENT_FAVORITE + contentShowVO.getId());
            Set<String> read = redisUtils.getSet(RedisContent.READ_NUM + contentShowVO.getId());
            contentShowVO.setSupportNum(supports.size());
            contentShowVO.setFavoriteNum(favorite.size());
            contentShowVO.setReadNum(read.size());
            contentShowVO.setFavorite(favorite.contains(SecurityUtils.getUserId()));
            contentShowVO.setSupport(supports.contains(SecurityUtils.getUserId()));
            return contentShowVO;
        });
    }

    @Override
    public List<ContentHotVO> getHot() {
        Set<String> zSet = redisUtils.getZSet(RedisContent.READ_SORT, 0, 50);
        if (ObjectUtil.isNull(zSet) || (ObjectUtil.isNotNull(zSet) && zSet.isEmpty())) {
            return new ArrayList<>();
        }
        return baseMapper.selectList(new LambdaQueryWrapper<Content>()
                .select(Content::getId, Content::getTitle)
                .in(Content::getId, zSet)).stream().map(content -> {
            ContentHotVO contentHotVO = new ContentHotVO();
            BeanUtils.copyProperties(content, contentHotVO);
            return contentHotVO;
        }).toList();
    }

    @Override
    public CountVO getCount(String userId) {
        CountVO countVO = new CountVO();
        String[] strings = baseMapper.selectList(new LambdaQueryWrapper<Content>()
                .eq(Content::getCreateUser, userId)).stream().map(Content::getId).toList().toArray(new String[0]);
        List<Long> countLua = redisUtils.getCountLua(strings);
        countVO.setFavoriteNum(countLua.get(0).intValue());
        countVO.setSupportNum(countLua.get(2).intValue());
        countVO.setReadNum(countLua.get(1).intValue());
        return countVO;
    }

}
